package xyz.ibenben.zhongdian.system.service.elasticsearch.impl;

import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.springframework.beans.BeanUtils;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;
import xyz.ibenben.zhongdian.common.annotation.SystemServiceLog;
import xyz.ibenben.zhongdian.system.entity.HouseImage;
import xyz.ibenben.zhongdian.system.entity.HouseInfo;
import xyz.ibenben.zhongdian.system.entity.HouseLocation;
import xyz.ibenben.zhongdian.system.entity.elasticsearch.ElasticsearchHouseInfo;
import xyz.ibenben.zhongdian.system.service.HouseImageService;
import xyz.ibenben.zhongdian.system.service.HouseLocationService;
import xyz.ibenben.zhongdian.system.service.elasticsearch.ElasticsearchHouseInfoService;
import xyz.ibenben.zhongdian.system.service.impl.RedisService;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;

/**
 * 房屋信息服务实现类
 * 提供了一些基本的服务，如根据主键查找房屋信息及图片、
 * 根据房屋名称查询记录、导出列表等方法。
 * 是此系统的主要服务类
 *
 * @author chenjian
 * @since 2017年9月27日上午10:57:28
 */
@Service
public class ElasticsearchHouseInfoServiceImpl extends AbstractElasticsearchServiceImpl<ElasticsearchHouseInfo>
        implements ElasticsearchHouseInfoService {
    @Resource
    private ElasticsearchTemplate elasticsearchTemplate;
    @Resource
    private HouseImageService houseImageService;
    @Resource
    private HouseLocationService houseLocationService;
    @Resource
    private RedisService redisService;

    /**
     * findOneWithImage房屋信息
     *
     * @param id 房屋主键
     * @return 房屋信息
     */
    @Override
    @SystemServiceLog(description = "findOneWithImage房屋信息")
    public ElasticsearchHouseInfo findOneWithImage(Long id) {
        ElasticsearchHouseInfo info = super.selectByKey(id);
        List<HouseImage> list = houseImageService.findByHouseId(id);
        if (list != null && !list.isEmpty()) {
            //为房屋信息设置图像列表
            info.setList(list);
        }
        return info;
    }

    /**
     * findByHouseName房屋信息
     *
     * @param houseName 房屋名称
     * @return 房屋信息列表
     */
    @Override
    @SystemServiceLog(description = "findByHouseName房屋信息")
    public List<ElasticsearchHouseInfo> findByHouseName(String houseName) {
        //通过房屋名称获取房屋信息列表
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(new MatchQueryBuilder("houseName", houseName).operator(Operator.AND)).build();
        return elasticsearchTemplate.queryForList(searchQuery, ElasticsearchHouseInfo.class);
    }

    /**
     * findByCreateIdAndType房屋信息
     *
     * @param createId 创建人主键
     * @param type     类型
     * @return 房屋信息列表
     */
    @Override
    @SystemServiceLog(description = "findByCreateIdAndType房屋信息")
    public List<ElasticsearchHouseInfo> findByCreateIdAndType(Long createId, int type) {
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(boolQuery().must(matchQuery("createId", createId))
                        .must(matchQuery("type", type))).build();
        return elasticsearchTemplate.queryForList(searchQuery, ElasticsearchHouseInfo.class);
    }

    /**
     * countAll获取所有房屋信息列表
     *
     * @return 封装好的Json对象
     */
    @Override
    @SystemServiceLog(description = "countAll获取所有房屋信息列表")
    public Map<String, Object> getHouseInfoList() {
        //Map结果集
        Map<String, Object> mapReturn = new HashMap<>(3);
        getHouseInfoListByEs("province", mapReturn);
        getHouseInfoListByEs("city", mapReturn);
        getHouseInfoListByEs("region", mapReturn);
        return mapReturn;
    }

    /**
     * 获取房屋数据给pie图
     *
     * @param type      1-省 2-市 3-县/区
     * @param mapReturn 返回数据
     * @return 名称/数量
     */
    private void getHouseInfoListByEs(String type, Map<String, Object> mapReturn) {
        String termsName;
        String fieldName;
        if ("province".equals(type)) {
            termsName = "all_provinces";
            fieldName = "provinceName.keyword";
        } else if ("city".equals(type)) {
            termsName = "all_cities";
            fieldName = "cityName.keyword";
        } else {
            termsName = "all_regions";
            fieldName = "regionName.keyword";
        }
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .addAggregation(AggregationBuilders.terms(termsName).field(fieldName)).build();
        Aggregations aggregations = elasticsearchTemplate.query(searchQuery, SearchResponse::getAggregations);
        StringTerms modelTerms = (StringTerms) aggregations.asMap().get(termsName);
        Map<String, Object> map = new HashMap<>(modelTerms.getBuckets().size());
        for (Terms.Bucket actionTypeBucket : modelTerms.getBuckets()) {
            //actionTypeBucket.getKey().toString()聚合字段的相应名称,actionTypeBucket.getDocCount()相应聚合结果
            map.put(actionTypeBucket.getKey().toString(), actionTypeBucket.getDocCount());
        }
        processMapReturn(map, mapReturn, type);
    }

    private void processMapReturn(Map<String, Object> map, Map<String, Object> mapReturn, String type) {
        if (map != null && !map.isEmpty()) {
            //为Echart放置数据，数据是否存在
            mapReturn.put(type + "PieExist", true);
            List<String> name = new ArrayList<>();
            List<String> values = new ArrayList<>();
            for (String keySet : map.keySet()) {
                name.add(keySet);
                values.add(map.get(keySet).toString());
            }
            //X轴
            mapReturn.put(type + "PieChatX", name);
            //Y轴
            mapReturn.put(type + "PieChatY", values);
        } else {
            //数据不存在
            mapReturn.put(type + "PieExist", false);
        }
    }

    @Override
    public void saveEntity(HouseInfo houseInfo, String entityName) {
        ElasticsearchHouseInfo info = processEntity(houseInfo);
        this.save(entityName, info);
    }

    @Override
    public void updateEntity(HouseInfo houseInfo, String entityName) {
        ElasticsearchHouseInfo info = processEntity(houseInfo);
        this.updateAll(entityName, info);
    }

    private ElasticsearchHouseInfo processEntity(HouseInfo houseInfo) {
        List<HouseImage> list = houseImageService.findByHouseId(houseInfo.getId());
        HouseLocation location = houseLocationService.selectByHouseId(houseInfo.getId());
        ElasticsearchHouseInfo info = new ElasticsearchHouseInfo();
        BeanUtils.copyProperties(houseInfo, info);
        info.setList(list);
        info.setProvinceName(redisService.get(houseInfo.getProvince()).toString());
        info.setCityName(redisService.get(houseInfo.getCity()).toString());
        info.setRegionName(redisService.get(houseInfo.getRegion()).toString());
        info.setOrientationName(houseInfo.getOrientation().getText());
        info.setTypeName(houseInfo.getType().getText());
        info.setHouseLocation(location);
        return info;
    }
}
